说明:创建对象有两种方式
类名 new
[[类名 alloc] init]
技巧:
Cocoa
惯例是使用后一种方式
10.1 分配对象
说明:就是从操作系统获得一块内存,并将其指定为存放对象的实例变量的位置。
语法:像某个类发送alloc
消息
alloc实例方法
说明:为类实例分配一块足够大的内存,并将这块内存区域全部初始化为对应的
0
值
实例变量类型 | 0 值 |
---|---|
BOOL | NO |
int | 0 |
float | 0.0 |
指针 | nil |
注意:刚刚分配的对象不能立即使用,初始化后才能使用。
Objective-C
将对象的创建拆分为两个明确的步骤:分配
和初始化
。
扩展:有些语言(包括c++
和java
)使用构造函数在一次操作中便执行完对象的分配和初始化。
1 | // 分配 |
10.1.1 初始化对象
说明:从操作系统取得一块内存(不一定是
分配
的内存)用于存储对象。
语法:通过嵌套方式向分配
操作的返回值发送init
消息。
注意:init
方法返回的对象可能与分配
的对象不同,因为某些类型底层其实是类蔟
。
错误示例
1 | Car *car = [Car alloc]; |
正确示例
1 | Car *car = [[Car alloc] init]; |
10.1.2 编写初始化方法
1 | (id) init { |
10.1.3 初始化时要做些什么
说明:有两种方式可以选择,取决于灵活性和性能的权衡
是否为实例变量创建对象 | 说明 | 适用 |
---|---|---|
是 | 方便,一步到位,出产即用 | 实例变量不需要定制 |
否 | 在某些情况下避免资源的浪费 | 实例变量需要定制 |
扩展:
惰性求值
,指的是即是目前没有设置自定义属性的值,也等到调用着需要时再创建对象,可以提高程序的性能。
10.2 便利初始化函数
说明:相比
init
,完成某些额外的初始化工作,名称以init
开头。
适用:加入对象必须要用某些信息进行初始化,那么应该将这些信息作为init方法的一部分添加进来。
initWithContentsofFile便利初始化方法
说明:打开指定路径上的文本文件,读取文件内容,并即用文件内容初始化为一个字符串。
原型:NSString
1 | >/** |
1 | // 错误 |
10.3 更多部件改进
注意:如果做
iOS
开发,由于不支持垃圾回收,必须使用ARC
技术。
10.3.1 Tire类的初始化
Tire.h
1 |
|
Tire.m
1 |
|
10.3.2 更新main()函数
既没有启用ARC
,也没有启用垃圾回收
的情形-手动管理
1 |
|
启用了ARC
或垃圾回收
1 |
|
10.3.3 清理Car类
Car.h
1 |
|
Car.m
1 |
|
10.4 Car 类的内存清理(垃圾回收方式和ARC方式)
说明:启用了
垃圾回收
或ARC
,则不用手动管理内存。
- 不再需要手动
释放
或保留
- 不需要重写
dealloc
方法完成内存的清理,如果要销毁时执行一些特别的操作,可以重写-finalize
方法注意:启用了
垃圾回收
则不需要@autoreleasepool
;启用ARC
,则代码中必要时仍然可以使用@autoreleasepool
。
构造便利初始化函数
说明:构造一个能同时获取轮胎压力和花纹深度的便利初始化函数。
Tire.h
1 | - (id) initWithPressure: (float) pressure treadDepth: (float) treadDepth; |
Tire.m
1 | - (id) initWithPressure: (float) p treadDepth: (float) td { |
main.m
1 | Tire *tire; |
10.5 指定初始化函数
说明:先增加几个
便利初始化函数
Tire.h
1 | - (id) initWithPressure: (float) pressure treadDepth: (float) treadDepth; |
Tire.m
1 | - (id) initWithPressure: (float) p treadDepth: (float) td { |
10.5.1 子类化问题
说明:
指定初始化函数
,即该中的某个初始化方法被指派为指定初始化函数,该类的所有初始化方法都调用指定初始化函数完成初始化。
技巧:通常,接收参数最多的初始化方法是最终的指定初始化函数。
问题描述
说明:
AllWeatherRadial
的超类Tire
中的构造器都没有使用指定初始化函数
,导致AllWeatherRadial
需要重写所有Tire
的构造器完成对自身实例变量的初始化。
AllWeatherRadial.h
1 |
|
AllWeatherRadial.m
1 |
|
10.5.2 Tire 类的初始化函数改进后的版本
说明:要解决上述问题,首先需要将
Tire
改造为使用指定初始化函数
的版本。
Tire.m
1 | - (id) init { |
10.5.3 添加AllWeatherPressure类的初始化函数
说明:然后,将
AllWeatherPressure
改造为使用指定初始化函数
的版本。只需要重载父类的指定初始化函数
,所有构造器就可以正常使用了(因为其他构造器都调用的指定初始化函数
)。
AllWeatherPressure.m
1 | - (id) initWithPressure: (float) p treadDepth: (float) td { |
10.6 初始化函数规则
说明:不是一定要为自己的类创建初始化函数
- 如果不需要设置任何状态,或者
alloc
方法将内存清零的默认行为相当不错,则不可以不设置指定初始化函数
。- 如果子类中创建类
指定初始化函数
,则一定要在这个制定初始化函数
中调用超类的指定初始化函数
。